/*
 * Copyright (c) 2011, Yawning <yawninglol at gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   * Neither the name of the Mew Developers nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package yawning.mew.protwarrior;

import yawning.mew.BuffsDebuffs;
import yawning.mew.MewProperty;
import yawning.mew.PropertiesBase;
import yawning.mew.BuffsDebuffs.Buff;
import yawning.mew.BuffsDebuffs.Debuff;
import yawning.mew.character.CharacterModel;
import yawning.mew.character.Clazz;
import yawning.mew.character.Glyph;
import yawning.mew.character.MetaGem;
import yawning.mew.character.Talent;
import yawning.mew.character.TalentTree;
import yawning.mew.character.Toon;

public class ProtWarriorModel extends CharacterModel {
    public static final MewProperty TIER_12_DPS_2PC = new MewProperty("Tier_12_Dps_2pc", false);
    public static final MewProperty TIER_13_DPS_2PC = new MewProperty("Tier_13_Dps_2pc", false);
	private static final MewProperty BUG_VENGEANCE_DECAY = new MewProperty("Bug.VengeanceDecay", false);		// The forced 5% Vengeance decay was shipped broken for 4.3

	protected Toon mToon;
	protected PropertiesBase mConfig;
	protected BuffsDebuffs mBuffsDebuffs;
	protected ProtWarriorStatLogic mLevelDep;

	protected ProtWarriorModel(Toon t, PropertiesBase config) {
		super(t);
		mToon = t;
		mConfig = config;
		mBuffsDebuffs = new BuffsDebuffs(mConfig.getProperties());
		mLevelDep = new ProtWarriorStatLogic(mStatLogic);
		calculateBaseStats();
	}

	@Override
	public double getAttackPower() {
		return((getStrength() - 10) * 2 + mToon.attackPower + bonusAttackPower) * apMult;
	}

	@Override
	public double getBlockChance() {
		double baseBlock = mStatLogic.getBaseBlock() + pSpecBlock - mTarget.getAvoidanceDepression();

		return Math.min(Math.max(0, baseBlock + bonusBlock + getCriticalBlockMastery()), 1.0);
	}

	public double getCriticalBlockChance(boolean holdTheLine) {
		double pMiss = getMissChance();
		double pDodge = getDodgeChance();
		double pParry = getParryChance();
		double pBlock = Math.max(0, mStatLogic.getBaseBlock() + pSpecBlock + bonusBlock + getCriticalBlockMastery() - mTarget.getAvoidanceDepression());

		double coverage = pMiss + pDodge + pParry + pBlock;
		if (coverage > 1.0 && bonusBlock > 0) {	// Yes, 1.0 not 1.024 because all the probabilities I have properly account for level delta.
			//
			// On overflow only the portion from Shield Block that causes you to shoot past full avoidance/mitigation
			// is applied to Crit. Block.  No double dipping Mastery Rating.
			//
			// Warning: This will blow up if I use addBlock() for anything other than Shield Block.
			//
			double pBlockNoSB = Math.max(0, mStatLogic.getBaseBlock() + pSpecBlock + getCriticalBlockMastery() - mTarget.getAvoidanceDepression());
			double pCoverageNoSB = pMiss + pDodge + pParry + pBlockNoSB;
			double pCritBlockSB = Math.max(0, bonusBlock - Math.max(0, 1.0 - pCoverageNoSB));
			return Math.min(getCriticalBlockMastery() + pCritBlockSB + ((holdTheLine) ? pCritBlockHoldTheLine : 0), 1.0);
		}

		return Math.min(getCriticalBlockMastery() + ((holdTheLine) ? pCritBlockHoldTheLine : 0), 1.0);
	}

	// Talents
	private static final TalentTree PROTECTION = TalentTree.get(Clazz.WARRIOR, "Protection");

	// Protection talents
	static final Talent INCITE = Talent.getByName(Clazz.WARRIOR, "Incite");
	static final Talent TOUGHNESS = Talent.getByName(Clazz.WARRIOR, "Toughness");
	static final Talent BLOODANDTHUNDER = Talent.getByName(Clazz.WARRIOR, "Blood and Thunder");

	static final Talent SHIELDSPECIALIZATION = Talent.getByName(Clazz.WARRIOR, "Shield Specialization");
	static final Talent SHIELDMASTERY = Talent.getByName(Clazz.WARRIOR, "Shield Mastery");
	static final Talent HOLDTHELINE = Talent.getByName(Clazz.WARRIOR, "Hold the Line");
	static final Talent GAGORDER = Talent.getByName(Clazz.WARRIOR, "Gag Order");

	static final Talent LASTSTAND = Talent.getByName(Clazz.WARRIOR, "Last Stand");
	static final Talent CONCUSSIONBLOW = Talent.getByName(Clazz.WARRIOR, "Concussion Blow");
	static final Talent BASTIONOFDEFENSE = Talent.getByName(Clazz.WARRIOR, "Bastion of Defense");
	static final Talent WARBRINGER = Talent.getByName(Clazz.WARRIOR, "Warbringer");

	static final Talent IMPROVEDREVENGE = Talent.getByName(Clazz.WARRIOR, "Improved Revenge");
	static final Talent DEVASTATE = Talent.getByName(Clazz.WARRIOR, "Devastate");
	static final Talent IMPENDINGVICTORY = Talent.getByName(Clazz.WARRIOR, "Impending Victory");

	static final Talent THUNDERSTRUCK = Talent.getByName(Clazz.WARRIOR, "Thunderstruck");
	static final Talent VIGILANCE = Talent.getByName(Clazz.WARRIOR, "Vigilance");
	static final Talent HEAVYREPERCUSSIONS = Talent.getByName(Clazz.WARRIOR, "Heavy Repercussions");

	static final Talent SAFEGUARD = Talent.getByName(Clazz.WARRIOR, "Safeguard");
	static final Talent SWORDANDBOARD = Talent.getByName(Clazz.WARRIOR, "Sword and Board");

	static final Talent SHOCKWAVE = Talent.getByName(Clazz.WARRIOR, "Shockwave");

	// Fury talents
	static final Talent BLOODCRAZE = Talent.getByName(Clazz.WARRIOR, "Blood Craze");
	static final Talent BATTLETRANCE = Talent.getByName(Clazz.WARRIOR, "Battle Trance");
	static final Talent CRUELTY = Talent.getByName(Clazz.WARRIOR, "Cruelty");

	static final Talent EXECUTIONER = Talent.getByName(Clazz.WARRIOR, "Executioner");		// Not modeled
	static final Talent BOOMINGVOICE = Talent.getByName(Clazz.WARRIOR, "Booming Voice");
	static final Talent RUDEINTERRUPTION = Talent.getByName(Clazz.WARRIOR, "Rude Interruption");
	static final Talent PIERCINGHOWL = Talent.getByName(Clazz.WARRIOR, "Piercing Howl");	// Not modeled

	// Arms talents
	static final Talent WARACADEMY = Talent.getByName(Clazz.WARRIOR, "War Academy");
	static final Talent FIELDDRESSING = Talent.getByName(Clazz.WARRIOR, "Field Dressing");
	static final Talent BLITZ = Talent.getByName(Clazz.WARRIOR, "Blitz");

	static final Talent TACTICALMASTERY = Talent.getByName(Clazz.WARRIOR, "Tactical Mastery");	// Not modeled
	static final Talent SECONDWIND = Talent.getByName(Clazz.WARRIOR, "Second Wind");	// Not modeled
	static final Talent DEEPWOUNDS = Talent.getByName(Clazz.WARRIOR, "Deep Wounds");
	static final Talent DRUMSOFWAR = Talent.getByName(Clazz.WARRIOR, "Drums of War");

	// Glyphs
	static final Glyph GLYPH_DEVASTATE = Glyph.getByName("Devastate");
	static final Glyph GLYPH_REVENGE = Glyph.getByName("Revenge");
	static final Glyph GLYPH_SHIELDSLAM = Glyph.getByName("Shield Slam");

	static final Glyph GLYPH_HEROICTHROW = Glyph.getByName("Heroic Throw");
	static final Glyph GLYPH_RAPIDCHARGE = Glyph.getByName("Rapid Charge");
	static final Glyph GLYPH_RESONATINGPOWER = Glyph.getByName("Resonating Power");
	static final Glyph GLYPH_SHIELDWALL = Glyph.getByName("Shield Wall");
	static final Glyph GLYPH_SHOCKWAVE = Glyph.getByName("Shockwave");
	static final Glyph GLYPH_THUNDERCLAP = Glyph.getByName("Thunder Clap");
	static final Glyph GLYPH_VICTORYRUSH = Glyph.getByName("Victory Rush");

	static final Glyph GLYPH_BATTLE = Glyph.getByName("Battle");
	static final Glyph GLYPH_BERSERKERRAGE = Glyph.getByName("Berserker Rage");
	static final Glyph GLYPH_COMMAND = Glyph.getByName("Command");
	static final Glyph GLYPH_DEMORALIZINGSHOUT = Glyph.getByName("Demoralizing Shout");
	static final Glyph GLYPH_ENDURINGVICTORY = Glyph.getByName("Enduring Victory");

	// Probabilities
	protected double pSpecBlock;
	protected double pCritBlockHoldTheLine;
	protected double pCritHoldTheLine;
	protected double pCritDevastateBonus;
	protected double pCritShieldSlamBonus;
	protected double pCritHeroicStrikeBonus;
	protected double pShieldBlockBlockProc = 0.25;
	protected double pBastionOfDefenseProc;
	protected double pSwordAndBoardProc;
	protected double pBattleTranceProc;
	protected double pBloodAndThunder;
	protected double pInciteProc;
	protected double pGagOrder;
	protected double pBloodCrazeProc;
	protected double pImpendingVictoryProc;
	protected double pCritRecklessness = 0.5;

	// Multipliers
	protected double multCrit;
	protected double multSpellCrit;
	protected double multHealCrit;
	protected double multPhysVuln;
	protected double multSpellVuln;
	protected double multBleedMult;
	protected double multBleedDarkIntent;
	protected double multDamageMult;
	protected double multHealSelf;
	protected double multHeal;
	protected double multThreatStance = 5.0;
	protected double multDRStance = 0.90;
	protected double multDRBlock;
	protected double multDRDemoralizingShout = 0.90;
	protected double multMagicDRShieldBlock;
	protected double multDRShieldWall = 0.60;
	protected double multDRRecklessness = 1.2;
	protected double multLastStandMaxHP = 1.3;
	protected double multBastionOfDefense;
	protected double multRudeInterruption = 1.05;
	protected double multDeepWoundsDamage;
	protected double multShieldSlamGlyph;
	protected double multShieldSlamShieldBlock;
	protected double multWarAcademyDamage;
	protected double multRevengeDamage;
	protected double multThunderstruckDamage;
	protected double multThunderstruckShockwaveDamage;
	protected double multThunderClap = 1.2;
	protected double multEnragedRegenerationHeal = 0.03;
	protected double multBloodCrazeHeal;
	protected double multVictoryRushHeal = 0.05;	// Impending Victory, don't care about other cases.

	// Durations
	protected int holdTheLineBuffDuration;
	protected int shieldBlockBuffDuration = 10;
	protected int shieldBlockCDDuration = 60;
	protected int shieldWallBuffDuration = 12;
	protected int shieldWallCDDuration = 300;
	protected int lastStandBuffDuration = 20;
	protected int lastStandCDDuration = 180;
	protected int demoralizingShoutDebuffDuration = 30;
	protected int bastionOfDefenseBuffDuration = 12;
	protected int pummelCDDuration = 10;
	protected int rudeInterruptionBuffDuration;
	protected int shoutCDDuration = 60;
	protected int berserkerRageCDDuration = 30;
	protected int berserkerRageBuffDuration = 10;
	protected int chargeCDDuration = 15;
	protected int chargeStunDuration = 1;
	protected int deepWoundsDotDuration = 6;
	protected int deepWoundsDotTickInterval = 1;
	protected int innerRageBuffDuration = 15;
	protected int innerRageCDDuration = 30;
	protected int swordAndBoardBuffDuration = 5;
	protected int shieldSlamCDDuration = 6;
	protected int battleTranceBuffDuration = 15;
	protected int sunderArmorDebuffDuration = 30;
	protected int revengeBuffDuration = 5;		// XXX: I think?
	protected int revengeCDDuration = 5;
	protected int thunderClapCDDuration = 6;
	protected int thunderClapDebuffDuration = 30;
	protected int thunderstruckBuffDuration = 20;
	protected int rendDotDuration = 15;
	protected int rendDotTickInterval = 3;
	protected int concussionBlowCDDuration = 30;
	protected int concussionBlowStunDuration = 5;
	protected int shockwaveCDDuration = 20;
	protected int shockwaveStunDuration = 4;
	protected int heroicStrikeCDDuration = 3;
	protected int inciteBuffDuration = 10;
	protected int heroicThrowCDDuration = 60;
	protected int enragedRegenerationBuffDuration = 10;
	protected int enragedRegenerationCDDuration = 180;
	protected int bloodCrazeBuffDuration = 5;
	protected int bloodCrazeTickInterval = 1;
	protected int victoryRushDuration = 20;
	protected int recklessnessCDDuration = 300;
	protected int recklessnessBuffDuration = 12;
	protected int retaliationCDDuration = 300;
	protected int retaliationBuffDuration = 12;

	// Costs
	protected int shieldBlockCost = 10;
	protected int demoralizingShoutCost = 10;
	protected int pummelCost = 10;
	protected int shieldSlamCost = 20;
	protected int devastateCost = 15;
	protected int revengeCost = 5;
	protected int thunderClapCost = 20;
	protected int rendCost = 10;
	protected int concussionBlowCost = 15;
	protected int shockwaveCost = 15;
	protected int heroicStrikeCost = 30;
	protected int cleaveCost = 30;

	// Set bonuses.
	protected double tier_11_2pc_ShieldSlamMult;
	protected double tier_12_2pc_damageMult = 0.2;
	protected double tier_12_2pc_dotDuration = 4;
	protected double tier_12_2pc_dotTickInterval = 2;
	protected double tier_12_4pc_bonusParry = 0.06;
	protected double tier_12_4pc_buffDuration = 10;
	protected double tier_12_dps_2pc_damageMult = 1.1;
	protected double tier_12_dps_2pc_buffDuration = 12;
	protected double tier_13_2pc_damageMult = 0.2;
	protected int tier_13_2pc_buffDuration = 10;		// XXX: Find this out for real.
	protected boolean mTier_12_dps_2pc;
	protected boolean mTier_13_dps_2pc;

	// Misc
	protected int shieldSpecRage;
	protected int shoutRage = 20;
	protected int berserkerRageRage;
	protected int chargeRage = 15;

	// Bugs
	protected boolean bug_pooledProcEffects;
	protected boolean bug_vengeanceDecay;

	private void calculateBaseStats() {
		// Agi, Str, AP.
		double statMult = mBuffsDebuffs.isBuff(Buff.STATMULT) ? 1.05 : 1;
		multiplyStrength(statMult);
		multiplyStamina(statMult);
		multiplyAgility(statMult);
		multiplyIntellect(statMult);

		int buffAgiStr = mBuffsDebuffs.isBuff(Buff.AGISTR) ? mStatLogic.getBuffAgiStr(): 0;
		addAgility(buffAgiStr);
		addStrength(buffAgiStr);

		multiplyAttackPower(mBuffsDebuffs.isBuff(Buff.APMULT) ? 1.2 : 1);

		addStamina(mBuffsDebuffs.isBuff(Buff.STAMINA) ? mStatLogic.getBuffStamina() : 0);
		addArmor(mBuffsDebuffs.isBuff(Buff.ARMOR) ? mStatLogic.getBuffArmor() : 0);

		multiplyStamina(mToon.mTalentSpec == PROTECTION ? 1.15 : 1);
		multiplyStamina(mToon.isArmorSpec ? 1.05 : 1);
		double toughnessMult = mToon.getTalent(TOUGHNESS) * 0.03;
		toughnessMult += (mToon.getTalent(TOUGHNESS) == 3) ? 0.01 : 0;
		multiplyBaseArmor(1 + toughnessMult);

		// Crit
		addMeleeCrit(mStatLogic.getBasePhysicalCrit());
		addMeleeCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addSpellCrit(mStatLogic.getBaseSpellCrit());
		addSpellCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addHealCrit(mStatLogic.getBaseSpellCrit());
		addHealCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addSpellCrit(mBuffsDebuffs.isDebuff(Debuff.SPELLCRIT) ? 0.05 : 0);

		// Haste
		multiplyHaste(mBuffsDebuffs.isBuff(Buff.DARKINTENT) ? 1.03 : 1);
		multiplyMeleeHaste(mBuffsDebuffs.isBuff(Buff.MELEEHASTE) ? 1.1 : 1);
		multiplySpellHaste(mBuffsDebuffs.isBuff(Buff.SPELLHASTE) ? 1.05 : 1);

		// Probabilities
		pSpecBlock = (mToon.mTalentSpec == PROTECTION) ? 0.15: 0;
		pCritBlockHoldTheLine = (mToon.getTalent(HOLDTHELINE) > 0) ? 0.10 : 0;
		pCritHoldTheLine = (mToon.getTalent(HOLDTHELINE) > 0) ? 0.10 : 0;
		pBastionOfDefenseProc = (mToon.getTalent(BASTIONOFDEFENSE) * 0.10);
		pSwordAndBoardProc = (mToon.getTalent(SWORDANDBOARD) * 0.10);
		pCritDevastateBonus = mToon.getTalent(SWORDANDBOARD) * 0.05 + (mToon.hasGlyph(GLYPH_DEVASTATE) ? 0.05 : 0);
		pCritShieldSlamBonus = mToon.getTalent(CRUELTY) * 0.05;
		pBattleTranceProc = mToon.getTalent(BATTLETRANCE) * 0.05;
		pBloodAndThunder = mToon.getTalent(BLOODANDTHUNDER) * 0.5;
		pCritHeroicStrikeBonus = mToon.getTalent(INCITE) * 0.05;
		pInciteProc = (mToon.getTalent(INCITE) == 3) ? 1.0 : mToon.getTalent(INCITE) * 0.33;
		pGagOrder = mToon.getTalent(GAGORDER) * 0.5;
		pBloodCrazeProc = mToon.getTalent(BLOODCRAZE) > 0 ? 0.10 : 0;
		pImpendingVictoryProc = mToon.getTalent(IMPENDINGVICTORY) * 0.25;

		// Multipliers
		multCrit = physicalCritMult;
		multSpellCrit = spellCritMult;
		multHealCrit = healCritMult;
		multPhysVuln = (mBuffsDebuffs.isDebuff(Debuff.PHYSVULN)) ? 1.04 : 1;
		multSpellVuln = (mBuffsDebuffs.isDebuff(Debuff.SPELLVULN)) ? 1.08 : 1;
		multBleedMult = (mBuffsDebuffs.isDebuff(Debuff.BLEEDDMG) ? 1.3 : 1);
		multBleedDarkIntent = ((mBuffsDebuffs.isBuff(Buff.DARKINTENT)) ? 1.03 : 1);
		multDamageMult = (mBuffsDebuffs.isBuff(Buff.DAMAGEMULT)) ? 1.03 : 1;
		multHealSelf = (1 + mToon.getTalent(FIELDDRESSING) * 0.03) * (1 + mToon.getTalent(FIELDDRESSING) * 0.1);
		multHeal = 1 + mToon.getTalent(FIELDDRESSING) * 0.03;
		multDRShieldWall -= (mToon.hasGlyph(GLYPH_SHIELDWALL)) ? 0.20 : 0;
		multiplyIncPhysicalDamage(multDRStance);
		multiplyIncMagicDamage(multDRStance);
		multiplyIncPhysicalDamage(mBuffsDebuffs.isBuff(Buff.PHYSDMGINC) ? 0.9 : 1);
		multBastionOfDefense = 1.0 + (mToon.getTalent(BASTIONOFDEFENSE) * 0.05);
		multDeepWoundsDamage = mToon.getTalent(DEEPWOUNDS) * 0.16;
		multShieldSlamGlyph = mToon.hasGlyph(GLYPH_SHIELDSLAM) ? 1.10 : 1.0;
		multShieldSlamShieldBlock =  1.0 + mToon.getTalent(HEAVYREPERCUSSIONS) * 0.5;
		multWarAcademyDamage = 1.0 + mToon.getTalent(WARACADEMY) * 0.05;
		multRevengeDamage = 1.0 + mToon.getTalent(IMPROVEDREVENGE) * 0.3 + (mToon.hasGlyph(GLYPH_REVENGE) ? 0.10 : 0);	// Additive stacking?
		multThunderstruckDamage = 1.0 + mToon.getTalent(THUNDERSTRUCK) * 0.03;	// Cleave/T. Clap/Rend
		multThunderstruckShockwaveDamage = mToon.getTalent(THUNDERSTRUCK) * 0.05;	// Per stack.
		multBloodCrazeHeal = mToon.getTalent(BLOODCRAZE) * 0.01 / bloodCrazeBuffDuration / bloodCrazeTickInterval;
		multVictoryRushHeal *= mToon.hasGlyph(GLYPH_VICTORYRUSH) ? 1.5 : 1;

		// Durations
		holdTheLineBuffDuration = mToon.getTalent(HOLDTHELINE) * 5;
		shieldBlockCDDuration -= mToon.getTalent(SHIELDMASTERY) * 10;
		shieldWallCDDuration += mToon.hasGlyph(GLYPH_SHIELDWALL) ? 120 : 0;
		shieldWallCDDuration -= mToon.getTalent(SHIELDMASTERY) * 60;
		demoralizingShoutDebuffDuration += mToon.hasGlyph(GLYPH_DEMORALIZINGSHOUT) ? 15 : 0;
		rudeInterruptionBuffDuration = mToon.getTalent(RUDEINTERRUPTION) * 15;
		shoutCDDuration -= mToon.getTalent(BOOMINGVOICE) * 15;
		chargeCDDuration -= mToon.hasGlyph(GLYPH_RAPIDCHARGE) ? 1 : 0;
		heroicThrowCDDuration -= mToon.getTalent(GAGORDER) * 15;
		victoryRushDuration += mToon.hasGlyph(GLYPH_ENDURINGVICTORY) ? 5 : 0;

		// Cost adjustment
		demoralizingShoutCost -= (mToon.getTalent(DRUMSOFWAR) * 5);
		pummelCost -= (mToon.getTalent(DRUMSOFWAR) * 5);
		thunderClapCost -= mToon.hasGlyph(GLYPH_RESONATINGPOWER) ? 5 : 0;

		// Misc
		addMobCrit(-(mToon.getTalent(BASTIONOFDEFENSE) * 0.03));
		multDRBlock = 1 - 0.3 + ((mToon.mMetaGem == MetaGem.ETERNAL) ? 0.01 : 0);
		double sbMagicMult = mToon.getTalent(SHIELDMASTERY) * 0.07;
		sbMagicMult -= (mToon.getTalent(SHIELDMASTERY) == 3) ? 0.01 : 0;
		multMagicDRShieldBlock = 1.0 - sbMagicMult;
		shieldSpecRage = mToon.getTalent(SHIELDSPECIALIZATION) * 5;
		shoutRage += mToon.getTalent(BOOMINGVOICE) * 5;
		berserkerRageRage = mToon.hasGlyph(GLYPH_BERSERKERRAGE) ? 5 : 0;
		chargeRage += mToon.getTalent(BLITZ) * 5;

		// Set/Equipment bonuses.
		//
		// Warrior T11 Protection 2P Bonus - Increases the damage done by your Shield Slam ability by 5%.
		// Warrior T11 Protection 4P Bonus - +50% Shield Wall Duration
		// Warrior T12 Protection 4P Bonus - When your Shield Block expires, your parry chance is increased by 6% for 10 sec.
		// Warrior T13 Protection 2P Bonus - Your Revenge ability now also grants a physical absorption shield equal to 20% of the damage done by Revenge.
		// Warrior T13 Protection 4P Bonus - (Not Implemented) Your Shield Wall ability now grants 50% of its effect to all party and raid members.
		//
		// Warrior T12 DPS 2P Bonus - Your Battle Shout and Commanding Shout abilities increase all physical damage you deal by 10% for 12 sec.
		// Warrior T13 DPS 2P Bonus - Heroic Strike costs 10 less rage while Inner Rage is active.
		//
		tier_11_2pc_ShieldSlamMult = mToon.tier_11_2pc ? 1.1 : 1.0;
		shieldWallBuffDuration += mToon.tier_11_4pc ? 6 : 0;
		mTier_12_dps_2pc = mConfig.getBool(TIER_12_DPS_2PC);
		mTier_13_dps_2pc = mConfig.getBool(TIER_13_DPS_2PC);

		// Blizzard bugs
		bug_pooledProcEffects = mConfig.getBool(BUG_POOLED_PROC_EFFECTS);
		bug_vengeanceDecay = mConfig.getBool(BUG_VENGEANCE_DECAY);
	}

	public final double getCriticalBlockMastery() {
		return getMastery() * 0.015;
	}

	public final double getNormalizedWeaponDamage() {
		// Assume the warrior is not a drooling retard and is using a 1h that is not a dagger.
		// I'd use 1.7 instead of 2.4 for a dagger, but fuck those retards.
		return 1 + (double) (mToon.weaponTop + mToon.weaponBottom) / 2  + bonusWeaponDamage + 2.4 * getAttackPower() / 14;
	}
}
